package com.yanqu.road.server.manger.scene;

import com.yanqu.road.entity.activity.ActivityInfo;
import com.yanqu.road.entity.scene.UserScene;
import com.yanqu.road.logic.pb.ScenePb;
import com.yanqu.road.pb.scene.SceneProto;
import com.yanqu.road.server.manger.player.GamePlayerMgr;
import com.yanqu.road.utils.YanQuMessageUtils;
import com.yanqu.road.server.protocol.CrossProtocol;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 本服场景
 * desc
 * 1. initActivity 把活动信息放进去，找不到或过期时，移除旧数据
 * 2. PERMANENT_ACTIVITY_ID 常驻系统用这个作为活动ID
 */
public class SceneMgr {

    // 常驻系统用的活动ID
    public static final int PERMANENT_ACTIVITY_ID = -1;

    // 日志
    private static Logger logger = LogManager.getLogger(SceneMgr.class.getName());

    // 场景锁
    private static final Object lockObject = new Object();

    // 活动信息          Map<活动ID，活动数据>
    private static Map<Integer, ActivityInfo> activityInfoMap = new ConcurrentHashMap<>();
    // 玩家              Map<用户ID，用户所在场景>
    private static Map<Long, UserScene> userMap = new ConcurrentHashMap<>();
    // 场景              Map<活动ID，类型，房间号，用户ID，用户所在场景>
    private static Map<Integer, Map<Integer, Map<String, Map<Long, UserScene>>>> sceneMap = new ConcurrentHashMap<>();

    /**
     * 初始化活动场景
     */
    public static void initActivity(ActivityInfo info) {
        if (info != null) {
            activityInfoMap.put(info.getActivityId(), info);
        }
    }

    /**
     * 进入场景
     * <p>
     * （如果有旧场景，且是不同活动的，则跨服退出）
     */
    public static boolean enterScene(UserScene userScene, boolean syncCross) {
        synchronized (lockObject) {
            // 能否操作
            UserScene oldScene = userMap.get(userScene.getUserId());
            if (oldScene != null && oldScene.getUpdateTime() >= userScene.getUpdateTime()) {
                return false;
            }
            // 退出旧场景
            if (oldScene != null) {
                userMap.remove(oldScene.getUserId());
                if (sceneMap.containsKey(oldScene.getActivityId()) &&
                        sceneMap.get(oldScene.getActivityId()).containsKey(oldScene.getSceneType()) &&
                        sceneMap.get(oldScene.getActivityId()).get(oldScene.getSceneType()).containsKey(oldScene.getSceneId())) {
                    sceneMap.get(oldScene.getActivityId()).get(oldScene.getSceneType()).get(oldScene.getSceneId()).remove(oldScene.getUserId());
                }
                // 跨服退出旧场景
                if (userScene.getActivityId() != oldScene.getActivityId()) {
                    oldScene.setUpdateTime(userScene.getUpdateTime() - 1);
                    crossSceneUpdate(oldScene, 2);
                }
            }
            // 初始化新场景
            if (!sceneMap.containsKey(userScene.getActivityId())) {
                sceneMap.put(userScene.getActivityId(), new ConcurrentHashMap<>());
            }
            if (!sceneMap.get(userScene.getActivityId()).containsKey(userScene.getSceneType())) {
                sceneMap.get(userScene.getActivityId()).put(userScene.getSceneType(), new ConcurrentHashMap<>());
            }
            if (!sceneMap.get(userScene.getActivityId()).get(userScene.getSceneType()).containsKey(userScene.getSceneId())) {
                sceneMap.get(userScene.getActivityId()).get(userScene.getSceneType()).put(userScene.getSceneId(), new ConcurrentHashMap<>());
            }
            // 加入新场景
            userMap.put(userScene.getUserId(), userScene);
            sceneMap.get(userScene.getActivityId()).get(userScene.getSceneType()).get(userScene.getSceneId()).put(userScene.getUserId(), userScene);
            // 同步跨服
            if (syncCross) {
                crossSceneUpdate(userScene, 1);
            }
            return true;
        }
    }

    /**
     * 退出场景
     */
    public static boolean quitScene(long userId, long updateTime, boolean syncCross) {
        synchronized (lockObject) {
            // 能否操作
            UserScene oldScene = userMap.get(userId);
            if (oldScene != null && oldScene.getUpdateTime() >= updateTime) {
                return false;
            }
            // 退出旧场景
            if (oldScene != null) {
                userMap.remove(oldScene.getUserId());
                if (sceneMap.containsKey(oldScene.getActivityId()) &&
                        sceneMap.get(oldScene.getActivityId()).containsKey(oldScene.getSceneType()) &&
                        sceneMap.get(oldScene.getActivityId()).get(oldScene.getSceneType()).containsKey(oldScene.getSceneId())) {
                    sceneMap.get(oldScene.getActivityId()).get(oldScene.getSceneType()).get(oldScene.getSceneId()).remove(oldScene.getUserId());
                }
                // 跨服退出
                if (syncCross) {
                    oldScene.setUpdateTime(updateTime);
                    crossSceneUpdate(oldScene, 2);
                }
            }
            return true;
        }
    }

    /**
     * 获取场景内全部玩家（用于同步）
     */
    public static List<UserScene> getSceneUserList(int activityId, int sceneType, String sceneId) {
        List<UserScene> userSceneList = new ArrayList<>();
        Map<Integer, Map<String, Map<Long, UserScene>>> map1 = sceneMap.get(activityId);
        if (map1 == null) return userSceneList;
        Map<String, Map<Long, UserScene>> map2 = map1.get(sceneType);
        if (map2 == null) return userSceneList;
        Map<Long, UserScene> map3 = map2.get(sceneId);
        if (map3 == null) return userSceneList;

        userSceneList = new ArrayList<>(map3.values());
        return userSceneList;
    }

    /**
     * 通知跨服刷新场景状态
     *
     * @param type 1进入，2退出
     */
    public static void crossSceneUpdate(UserScene userScene, int type) {
        if (userScene.getActivityId() != 0) {
            SceneProto.CrossUpdateSceneReqMsg.Builder sceneBuilder = SceneProto.CrossUpdateSceneReqMsg.newBuilder();
            sceneBuilder.setActivityId(userScene.getActivityId());
            sceneBuilder.setSceneMsg(ScenePb.parseSceneMsg(userScene));
            sceneBuilder.setType(type);
            GamePlayerMgr.sendPacket(0, YanQuMessageUtils.buildMessage(CrossProtocol.C2_CROSS_SCENE_UPDATE, sceneBuilder));
        }
    }

    /**
     * 清理旧数据
     */
    public static void cleanOldData() {
        synchronized (lockObject) {
            long now = System.currentTimeMillis() / 1000;
            for (Map.Entry<Integer, Map<Integer, Map<String, Map<Long, UserScene>>>> activityEntry : sceneMap.entrySet()) {
                if (activityEntry.getKey() == PERMANENT_ACTIVITY_ID) {
                    continue;
                }
                ActivityInfo info = activityInfoMap.get(activityEntry.getKey());
                if (info == null || info.getEndShowTime() < now) {
                    sceneMap.remove(activityEntry.getKey());
                    activityInfoMap.remove(activityEntry.getKey());
                }
            }
        }
    }
}
